package cn.xu.tool.big.a.compments.transaction;

import cn.xu.tool.big.a.compments.strategy.TradingStrategy;
import cn.xu.tool.big.a.dto.KLine;
import cn.xu.tool.big.a.dto.TotalReturn;
import cn.xu.tool.big.a.dto.TradeRecord;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * 类名: TransactionTest
 * 描述: TODO
 * 作者: ClarkXu clark2021@qq.com
 * 日期: 2025/7/8
 */
public class TransactionCp {

    public static List<TradeRecord> doTransactionBt(List<KLine> kLines, String stockCode, String startDate, String endDate,
                                                    double initialCapital, double commissionRate,
                                                    TotalReturn totalReturn) throws Exception {
        // 3. 生成交易信号
        int[] signals = TradingStrategy.generateSignals(kLines, 5, 20);

        // 4. 回测
        return backtest(kLines, signals, initialCapital, commissionRate, totalReturn, false);
    }

    // 回测双均线策略
    public static List<TradeRecord> backtest(List<KLine> kLines, int[] signals,
                                             double initialCapital, double commissionRate,
                                             TotalReturn totalReturn, boolean allSell) {
        double capital = initialCapital;
        int totalPosition = 0; // 持有股票数量
        int tmpPosition = 0;
        double buyVolume = 0;
        double sellVolume = 0;
        double buyPrice = 0; // 买入价格
        int tradeCount = 0; // 交易次数
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        List<TradeRecord> records = new ArrayList<>();
        System.out.println("日期\t\t操作\t价格\t\t\t\t仓位\t\t\t现金\t\t\t总资产");
        for (int i = 0; i < kLines.size(); i++) {
            KLine kLine = kLines.get(i);
            int signal = signals[i];
            double price = kLine.getClose(); // 以收盘价交易

            // 执行买入信号
            if (signal == 1 && capital > 0) {
                // 计算可以买入的股票数量（假设可以买任意股数，实际交易是整手）
                double amount = capital * (1 - commissionRate); // 扣除手续费后的可用资金
                tmpPosition = (int)(amount / price); // 买入所有可用资金能买的股票数量
                tmpPosition = tmpPosition-tmpPosition%100;//最小成交量100
                if(tmpPosition>=100){
                    totalPosition += tmpPosition;
                    capital = capital - tmpPosition * price; // 现金全部用完
                    buyPrice = price;
                    tradeCount++;
                    System.out.printf("%s\t买入\t%.2f\t%d\t%.2f\t%.2f\n",
                            kLine.getDate(), price, totalPosition, capital, capital + totalPosition * price);
                    records.add(TradeRecord.create(kLine.getDate(), "买入", price, totalPosition, capital, capital + totalPosition * price, tmpPosition));
                }
            }
            // 执行卖出信号
            else if (signal == -1 && totalPosition > 0) {
                double value = totalPosition * price; // 卖出股票所得
                capital = value * (1 - commissionRate); // 扣除手续费
                int tmpVolume = totalPosition;
                totalPosition = 0; // 清空仓位
                tradeCount++;
                System.out.printf("%s\t卖出\t%.2f\t%d\t%.2f\t%.2f\n",
                        kLine.getDate(), price, totalPosition, capital, capital);
                records.add(TradeRecord.create(kLine.getDate(), "卖出", price, totalPosition, capital, capital, tmpVolume));
            }

            // 每日总资产 = 现金 + 股票市值
            double total = capital + totalPosition * price;
            // 如果不是交易信号，输出持仓情况
            if (signal == 0) {
//                System.out.printf("%s\t持仓\t%.2f\t%d\t%.2f\t%.2f\n",
//                        kLine.getDate(), price, position, capital, total);
                records.add(TradeRecord.create(kLine.getDate(), "持仓", price, totalPosition, capital, total, 0));
            }
        }

        if(allSell){
            // 最后一天如果还有持仓，按最后一天收盘价卖出
            if (totalPosition > 0) {
                KLine last = kLines.get(kLines.size() - 1);
                double price = last.getClose();
                double value = totalPosition * price;
                capital = value * (1 - commissionRate);
                int tmpVolume = totalPosition;
                totalPosition = 0;
                System.out.printf("%s\t强制平仓\t%.2f\t%d\t%.2f\t%.2f\n",
                        last.getDate(), price, totalPosition, capital, capital);
                records.add(TradeRecord.create(last.getDate(), "强制平仓", price, totalPosition, capital, capital, tmpVolume));
            }
        }else{
            //按最后一天
            if (totalPosition > 0) {
                KLine last = kLines.get(kLines.size() - 1);
                double price = last.getClose();
                double value = totalPosition * price;
                capital = value * (1 - commissionRate);
                int tmpVolume = totalPosition;
                totalPosition = 0;
                System.out.printf("%s\t强制平仓\t%.2f\t%d\t%.2f\t%.2f\n",
                        last.getDate(), price, totalPosition, capital, capital);
                records.add(TradeRecord.create(last.getDate(), "强制平仓", price, totalPosition, capital, capital, tmpVolume));
            }
        }
        // 计算总收益
        double finalReturn = capital - initialCapital;
        double returnRate = finalReturn / initialCapital * 100;
        System.out.println("初始资金: " + initialCapital);
        System.out.println("最终资金: " + capital);
        System.out.println("总收益率: " + String.format("%.2f", returnRate) + "%");
        System.out.println("交易次数: " + tradeCount);
        totalReturn.setInitialCapital(initialCapital);
        totalReturn.setFinalCapital(capital);
        totalReturn.setReturnRate(String.format("%.2f", returnRate) + "%");
        totalReturn.setTradeCount(tradeCount);
        return records;
    }
}
